﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;

using System.Xml.Serialization;
using System.IO;
using System.Windows.Controls;
using System.Text.RegularExpressions;
using KTVConsole2.Util;
using System.Windows.Threading;
using MediaInfoWrapper;
using WindowsInput;
using System.Runtime.InteropServices;



namespace KTVConsole2.Core
{
    public class KtvEngine
    {
        /// <summary>
        /// 当前点播歌曲列表
        /// </summary>
        /// 
        [XmlIgnore]
        public System.Collections.ObjectModel.ObservableCollection<Song> PlayList { get { return playList; } }
        private System.Collections.ObjectModel.ObservableCollection<Song> playList = new ObservableCollection<Song>();
        private NLog.Logger log = NLog.LogManager.GetCurrentClassLogger();
        
        /// <summary>
        /// 搜索结果
        /// </summary>
        [XmlIgnore]
        public System.Collections.ObjectModel.ObservableCollection<Song> SearchList { get { return searchList; } }
        [XmlIgnore]
        private System.Collections.ObjectModel.ObservableCollection<Song> searchList = new ObservableCollection<Song>();

        /// <summary>
        /// 保存的歌曲列表
        /// </summary>
        public System.Collections.ObjectModel.ObservableCollection<FavoriteSongs> MyPlayList { get { return myPlayList; } }
        private System.Collections.ObjectModel.ObservableCollection<FavoriteSongs> myPlayList = new ObservableCollection<FavoriteSongs>();

        /// <summary>
        /// 所有歌曲
        /// </summary>
        /// 
        private List<Song> allSongs = new List<Song>();
        public List<Song> AllSongs { get { return allSongs; } }

        private static string XmlFilePath = "songsdb.xml";
        private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();

        static Regex rgSongName = new Regex(@"'歌名', '(.*)'\);", RegexOptions.Compiled);
        static Regex rgGeShou = new Regex(@"'歌手', '(.*)'\);", RegexOptions.Compiled);
        static Regex rgPath = new Regex(@"karaoke.CommonVideo := '(.*)';", RegexOptions.Compiled);

        private int seeds = 0;

        private KtvEngine()
        {
            timer.Tick += new EventHandler(timer_Tick);
        }

        void timer_Tick(object sender, EventArgs e)
        {
            timer.Enabled = false;
            OnPlayedRaised(PlayedRaisedEventArgs.Empty);
        }

        public event EventHandler<PlayedRaisedEventArgs> PlayedRaised;

        protected virtual void OnPlayedRaised(PlayedRaisedEventArgs e)
        {
            EventHandler<PlayedRaisedEventArgs> handler = PlayedRaised;
            if (handler != null)
                handler(this, e);
        }

        /// <summary>
        /// 从xml文件装载
        /// </summary>
        public static KtvEngine GetInstance()
        {
            if (File.Exists(XmlFilePath))
                return Util.Util.XmlDeserialize<KtvEngine>(XmlFilePath);
            else
                return new KtvEngine();
        }

        public static KtvEngine GetInstance(string xmlFilePath)
        {
            XmlFilePath = xmlFilePath;
            return GetInstance();
        }

        public static void SetXmlFilePath(string path)
        {
            XmlFilePath = path;
        }

        /// <summary>
        /// 保存到xml文件
        /// </summary>
        public void SaveToXML()
        {
            XmlSerializer ser = new XmlSerializer(this.GetType());
            string path = XmlFilePath;
            using (Stream s = File.Open(path, System.IO.FileMode.Create, System.IO.FileAccess.Write))
            {
                try
                {
                    ser.Serialize(s, this);
                }
                catch (Exception e)
                {
                    s.Close();
                    try
                    {
                        File.Delete(path);
                    }
                    catch (IOException) { }
                    Console.Write(e.Message);
                    Util.Util.TellUser(e.Message);
                }
            }
        }

        /// <summary>
        /// 播放歌曲
        /// </summary>
        /// <returns>返回歌曲播放时间(ms)。返回值为0，说明没有此歌曲，或者不能获取歌曲长度信息</returns>
        public int Play()
        {
            timer.Enabled = false;
            if (playList.Count == 0)
            {
                Util.Util.TellUser("请先点播歌曲");
                return 0;
            }
            var path = playList[0].Path;
            if (File.Exists(path))
            {
                MediaInfo mi = new MediaInfo(path);
                int duration = 0;
                if (mi.AudioCount > 0)
                {
                    duration = int.Parse(mi.Audio[0].Duration);
                }
                playList[0].AudioCount = mi.AudioCount;
                playList[0].Duration = duration;
                string currentPath = System.Environment.CurrentDirectory;
                string potPath = currentPath + "\\tools\\PotPlayer\\" + "PotPlayerMini.exe";
                log.Debug("potplayer path: " + potPath);
                System.Diagnostics.Process.Start(potPath, path);
                timer.Interval = (int)duration;
                timer.Enabled = true;
                return duration;
            }
            else
            {
                Util.Util.TellUser("找不到这首歌：" + path);
                return 0;
            }
        }

        public void Close()
        {
            SaveToXML();
        }

        public void PlayNext()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// CTRL+ALT+F1
        /// </summary>
        public void ToggleFullScreen()
        {
            if (playList.Count == 0)
            {
                Util.Util.TellUser("还没点歌呢，就切全屏！");
            }
            var sim = new KeyboardSimulator();
            //sim.ModifiedKeyStroke(WindowsInput.Native.VirtualKeyCode.CONTROL, WindowsInput.Native.VirtualKeyCode.F9);
            WindowsInput.Native.VirtualKeyCode[] modifierKeyCodes = {WindowsInput.Native.VirtualKeyCode.CONTROL, WindowsInput.Native.VirtualKeyCode.MENU};
            sim.ModifiedKeyStroke(modifierKeyCodes, WindowsInput.Native.VirtualKeyCode.F1);
        }
        
        /// <summary>
        /// 切换音轨。CTRL+ALT+F3, F4, F5, 这是立体声、左、右声道。 CTRL+ALT+F2, 这是声轨切换。注意在播放器中设置好快捷键。
        /// </summary>
        public virtual void ToggleTrack()
        {
            if (playList.Count == 0)
            {
                Util.Util.TellUser("还没点歌呢，就切音轨！");
                return;
            }
            var sim = new KeyboardSimulator();
            Song operUnit = playList[0];
            WindowsInput.Native.VirtualKeyCode[] modifierKeyCodes = { WindowsInput.Native.VirtualKeyCode.CONTROL, WindowsInput.Native.VirtualKeyCode.MENU };
            if (playList[0].AudioCount == 1)
            {                
                if (operUnit.CurrentAudioLeftOrRight == 0)
                {
                    //SendKeys.SendWait("^1"); // 切换到左声道
                    sim.ModifiedKeyStroke(modifierKeyCodes, WindowsInput.Native.VirtualKeyCode.F4);
                    operUnit.CurrentAudioLeftOrRight = 1;
                }
                else if (operUnit.CurrentAudioLeftOrRight == 1)
                {
                    //SendKeys.SendWait("^2"); // 切换到右声道
                    sim.ModifiedKeyStroke(modifierKeyCodes, WindowsInput.Native.VirtualKeyCode.F5);
                    operUnit.CurrentAudioLeftOrRight = 2;
                }
                else if (operUnit.CurrentAudioLeftOrRight == 2)
                {
                    //SendKeys.SendWait("^3"); // 切换到全声道
                    sim.ModifiedKeyStroke(modifierKeyCodes, WindowsInput.Native.VirtualKeyCode.F3);
                    operUnit.CurrentAudioLeftOrRight = 0;
                }
            
            }
            else
            {
                if (operUnit.CurrentAudioLeftOrRight == 0)
                {
                    //SendKeys.SendWait("^1"); // 切换到左声道
                    sim.ModifiedKeyStroke(modifierKeyCodes, WindowsInput.Native.VirtualKeyCode.F2);
                    operUnit.CurrentAudioLeftOrRight = 1;
                }
                else if (operUnit.CurrentAudioLeftOrRight == 1)
                {
                    //SendKeys.SendWait("^2"); // 切换到右声道
                    sim.ModifiedKeyStroke(modifierKeyCodes, WindowsInput.Native.VirtualKeyCode.F2);
                    operUnit.CurrentAudioLeftOrRight = 0;
                }
            }
        }

        public void SearchSong(string searchText, bool? includeStar, bool? includeSongName)
        {
            //log.Debug("search start");
            if (searchText.Trim() == "")
            {
                searchList = new ObservableCollection<Song>(allSongs);
                //log.Debug("Search end");
                return;
            }
            IEnumerable<Song> rst;
            if (includeStar == false && includeSongName == true)
                rst = from a in allSongs
                      where
                          a.SongName.ToUpper().Contains(searchText)
                          || a.SongNamePinYin.ToUpper().Contains(searchText)
                          || a.SongNameJianPin.ToUpper().Contains(searchText)
                      select a;
            else if (includeStar == true && includeSongName == false)
                rst = from a in allSongs
                      where a.Star.ToUpper().Contains(searchText)
                          || a.StarPinYin.ToUpper().Contains(searchText)
                          || a.StarJianPin.ToUpper().Contains(searchText)
                      select a;
            else
                rst = from a in allSongs
                      where a.Star.ToUpper().Contains(searchText)
                          || a.StarPinYin.ToUpper().Contains(searchText)
                          || a.StarJianPin.ToUpper().Contains(searchText)
                          || a.SongName.ToUpper().Contains(searchText)
                          || a.SongNamePinYin.ToUpper().Contains(searchText)
                          || a.SongNameJianPin.ToUpper().Contains(searchText)
                      select a;

            searchList = new System.Collections.ObjectModel.ObservableCollection<Song>(rst);
            //log.Debug("search end");
        }


        internal double GetTotalSongsInDir(DirectoryInfo dir, SearchOption opt)
        {
            return dir.GetFiles("*.ksc", opt).Length;            
        }

        internal void ScanSongs(DirectoryInfo ktvLib, SearchOption opt, Util.UpdateProgressBarDelegate updateProcessDelegate)
        {
            allSongs.Clear();
            playList.Clear();
            var a = ktvLib.GetFiles("*.ksc", opt);
            List<System.IO.FileInfo> allFiles = new List<System.IO.FileInfo>();
            allFiles.AddRange(a);
            int totalFile = allFiles.Count;
            double current = 0;
            foreach (var aa in allFiles)
            {
                addSongFromKscFile(aa);
                current++;
                System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke(updateProcessDelegate, System.Windows.Threading.DispatcherPriority.Background, new object[] { ProgressBar.ValueProperty, current });
            }
            SaveToXML();
        }

        private void addSongFromKscFile(FileInfo aa)
        {
            Song song = GetSongInformationFromKscFile(aa.FullName);
            if (song == null)
                return;
            song.Duration = 0;
            song.AudioCount = 0;
            song.CurrentAudioLeftOrRight = 0;
            allSongs.Add(song);
        }

        private Song GetSongInformationFromKscFile(string file)
        {
            if (!File.Exists(file))
                return null;
            using (StreamReader sr = new StreamReader(file, Encoding.GetEncoding("GBK")))
            {
                string line = "";
                Song song = new Song();
                while (sr.Peek() >= 0)
                {
                    line = sr.ReadLine();
                    ParseLine(line, song);
                }
                if (!string.IsNullOrEmpty(song.Path))
                {
                    song.Path = Path.GetDirectoryName(file) + "\\" + song.Path;
                }
                return song;
            }
        }

        private void ParseLine(string line, Song song)
        {
            if (rgSongName.IsMatch(line))
            {
                song.SongName = rgSongName.Match(line).Groups[1].Value;
                song.SongNameJianPin = Chinese2Pinyin.Chinese2Pinyin.Convert2FirstLetter(song.SongName);
                song.SongNamePinYin = Chinese2Pinyin.Chinese2Pinyin.Convert2Pinyin(song.SongName);
            }
            else if (rgGeShou.IsMatch(line))
            {
                song.Star = rgGeShou.Match(line).Groups[1].Value;
                song.StarJianPin = Chinese2Pinyin.Chinese2Pinyin.Convert2FirstLetter(song.Star);
                song.StarPinYin = Chinese2Pinyin.Chinese2Pinyin.Convert2Pinyin(song.Star);
            }
            else if (rgPath.IsMatch(line))
            {
                song.Path = rgPath.Match(line).Groups[1].Value;
            }
        }

        /// <summary>
        /// 在播放列表中增加一首歌。
        /// </summary>
        /// <param name="song"></param>
        public void AddSongToPlayList(Song _song)
        {
            var song = _song.Clone() as Song;
            if (playList.Count == 0)
            {
                song.Id = 0;
            }
            else
            {
                seeds++;
                song.Id = seeds;
            }
            playList.Add(song);
        }
    }

    public class PlayedRaisedEventArgs : EventArgs
    {
        public static readonly PlayedRaisedEventArgs Empty = new PlayedRaisedEventArgs();
    }


}
